#include "XHCPConnection.h"
#include <QStringList>

static inline QByteArray IntToArray(qint32 source);

XHCPConnection::XHCPConnection(const QString& connectionName, QObject *parent)
    : QObject(parent),
      m_socket(new QTcpSocket(this)),
      m_connectionName(connectionName)
{
    connect(m_socket, SIGNAL(connected()), this, SLOT(onServerConnected()));
    connect(m_socket, SIGNAL(disconnected()), this, SLOT(onServerDisconnected()));
    connect(m_socket, SIGNAL(readyRead()), this, SLOT(onServerDataReceived()));
    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onServerError(QAbstractSocket::SocketError)));

}

XHCPConnection::~XHCPConnection()
{

}

void XHCPConnection::setConnectionOptions(const QHostAddress &host, int port)
{
    setHostAddress(host);
    setPort(port);
}


void XHCPConnection::open()
{
    if(m_socket) {
        m_socket->connectToHost(m_hostAddress, m_port);
    }
}

void XHCPConnection::close()
{
    if(m_socket) {
        m_socket->close();
    }
}

bool XHCPConnection::sendData(QByteArray data)
{
    if(m_socket
            && m_socket->state() == QAbstractSocket::ConnectedState)
    {
        m_socket->write(IntToArray(data.size())); //write size of data
        m_socket->write(data); //write the data itself
        return m_socket->waitForBytesWritten();
    }
    else
        return false;
}

void XHCPConnection::onServerConnected()
{
    qDebug() << "server connected";
}

void XHCPConnection::onServerDisconnected()
{
    qDebug() << "server diconnected";
}

void XHCPConnection::onServerDataReceived()
{
    if(!m_socket) return;
    qDebug() << "server data received";
    m_pendingData += m_socket->readAll();
    bool conversionOK = false;
    int messageCode = m_pendingData.left(3).toInt(&conversionOK);
    if(!conversionOK) {
        // No XHCP header -> scrap the data
        m_pendingData = "";
        qDebug() << "data scrapped !";
        return;
    }
    if(messageCode == 200) {
        int end = m_pendingData.indexOf("\r\n");
        if(end < 0) {
            return;
        }
        int charcount = end + 2;
        QString data = m_pendingData.left(charcount);
        qDebug() << "data = " << data;
        m_pendingData = m_pendingData.right(m_pendingData.count() - charcount);
        qDebug() << "rest = " << m_pendingData;
    }
    if(messageCode == 216) {
        int end = m_pendingData.indexOf("\r\n.\r\n");
        if(end < 0) {
            // incomplete data. Wait the next packet before processing...
            return;
        }
        int charcount = end+5;
        QString data = m_pendingData.left(charcount-1);
        qDebug() << "data = " << data;
        m_pendingData = m_pendingData.right(m_pendingData.count()-charcount);
        qDebug() << "rest = " << m_pendingData;
        qDebug() << "processing device list ...";
        QStringList list = data.split("\r\n");
        if(list.count() <= 1) {
            qDebug() << "no device in xpl server...";
            return;
        }
        for(int i = 1; i < list.count()-1; i++) {
            qDebug() << "device: " << list.at(i);
        }
    }
}

void XHCPConnection::onServerError(QAbstractSocket::SocketError error)
{

}

void XHCPConnection::requestListAllDevs()
{
    qDebug() << "sending data...";
    QString request = "LISTALLDEVS\r\n";
    if(!sendData(request.toLocal8Bit()))
        qDebug() << "Failed to send data to server";
    qDebug() << "LISTALLDEVS sent";
}

bool XHCPConnection::isOpen() const
{
    return (m_socket && m_socket->isOpen());
}

QByteArray IntToArray(qint32 source) //Use qint32 to ensure that the number have 4 bytes
{
    //Avoid use of cast, this is the Qt way to serialize objects
    QByteArray temp;
    QDataStream data(&temp, QIODevice::ReadWrite);
    data << source;
    return temp;
}
